package com.jinlin.test;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by J!nl!n on 15/12/1.
 * Copyright © 1990-2015 J!nl!n™ Inc. All rights reserved.
 * <p/>
 * ━━━━━━神兽出没━━━━━━
 * 　　　┏┓　　　┏┓
 * 　　┏┛┻━━━┛┻┓
 * 　　┃　　　　　　　┃
 * 　　┃　　　━　　　┃
 * 　　┃　┳┛　┗┳　┃
 * 　　┃　　　　　　　┃
 * 　　┃　　　┻　　　┃
 * 　　┃　　　　　　　┃
 * 　　┗━┓　　　┏━┛Code is far away from bug with the animal protecting
 * 　　　　┃　　　┃    神兽保佑,代码无bug
 * 　　　　┃　　　┃
 * 　　　　┃　　　┗━━━┓
 * 　　　　┃　　　　　　　┣┓
 * 　　　　┃　　　　　　　┏┛
 * 　　　　┗┓┓┏━┳┓┏┛
 * 　　　　　┃┫┫　┃┫┫
 * 　　　　　┗┻┛　┗┻┛
 * ━━━━━━感觉萌萌哒━━━━━━
 */
public class TagsFlowlayout extends ViewGroup {

    private final int default_border_color = Color.rgb(0x49, 0xC1, 0x20);
    private final int default_text_color = Color.rgb(0x49, 0xC1, 0x20);
    private final int default_background_color = Color.WHITE;
    private final int default_checked_border_color = Color.rgb(0x49, 0xC1, 0x20);
    private final int default_checked_text_color = Color.WHITE;
    private final int default_checked_background_color = Color.rgb(0x49, 0xC1, 0x20);
//    private final int default_pressed_background_color = Color.rgb(0xED, 0xED, 0xED);
    private final int default_pressed_background_color = Color.TRANSPARENT;

    private int textColor;
    private int backgroundColor;
    private int checkedTextColor;
    private int checkedBackgroundColor;
    private int pressedBackgroundColor;

    //textview的属性
    private float mRadius[] = {0, 0, 0, 0, 0, 0, 0, 0};
    private int mStrokeColor, mCheckedStrokeColor;
    private int mStrokeWidth = 0;


    private float textSize;
    private int horizontalSpacing;
    private int verticalSpacing;
    private int horizontalPadding;
    private int verticalPadding;
    private int tagWidth, tagHeight;
    private boolean multiChooseable;

    private OnTagClickListener mOnTagClickListener;

    private InternalTagClickListener mInternalTagClickListener = new InternalTagClickListener();

    public TagsFlowlayout(Context context) {
        this(context, null);
    }

    public TagsFlowlayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TagsFlowlayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        float default_text_size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 13.0f, getResources().getDisplayMetrics());
        float default_horizontal_spacing = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8.0f, getResources().getDisplayMetrics());
        float default_vertical_spacing = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4.0f, getResources().getDisplayMetrics());
        float default_horizontal_padding = 0.0f;
        float default_vertical_padding = 0.0f;

        final TypedArray attrsArray = context.obtainStyledAttributes(attrs, R.styleable.TagsFlowlayout, defStyleAttr, R.style.FlowlayoutTags);
        try {
            textColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_textColor, default_text_color);
            backgroundColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_backgroundColor, default_background_color);
            checkedTextColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_checkedTextColor, default_checked_text_color);
            checkedBackgroundColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_checkedBackgroundColor, default_checked_background_color);
            pressedBackgroundColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_pressedBackgroundColor, default_pressed_background_color);
            textSize = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_textSize, default_text_size);
            horizontalSpacing = (int) attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_horizontalSpacing, default_horizontal_spacing);
            verticalSpacing = (int) attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_verticalSpacing, default_vertical_spacing);
            horizontalPadding = (int) attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_horizontalPadding, default_horizontal_padding);
            verticalPadding = (int) attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_verticalPadding, default_vertical_padding);
            multiChooseable = attrsArray.getBoolean(R.styleable.TagsFlowlayout_tag_multiChooseable, true);
            tagWidth = attrsArray.getInt(R.styleable.TagsFlowlayout_tag_width, TagsFlowlayout.LayoutParams.WRAP_CONTENT);
            if (tagWidth >= 0) {
                tagWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tagWidth, getResources().getDisplayMetrics());
            }
            tagHeight = attrsArray.getInt(R.styleable.TagsFlowlayout_tag_height, TagsFlowlayout.LayoutParams.WRAP_CONTENT);
            if (tagHeight >= 0) {
                tagHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tagHeight, getResources().getDisplayMetrics());
            }

            float radius = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_radius, 0);
            float topLeftRadius = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_topLeftRadius, 0);
            float topRightRadius = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_topRightRadius, 0);
            float bottomLeftRadius = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_bottomLeftRadius, 0);
            float bottomRightRadius = attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_bottomRightRadius, 0);

            if (topLeftRadius == 0 && topRightRadius == 0 && bottomLeftRadius == 0
                    && bottomRightRadius == 0) {
                topLeftRadius = topRightRadius = bottomRightRadius = bottomLeftRadius = radius;
            }

            mRadius[0] = mRadius[1] = topLeftRadius;
            mRadius[2] = mRadius[3] = topRightRadius;
            mRadius[4] = mRadius[5] = bottomRightRadius;
            mRadius[6] = mRadius[7] = bottomLeftRadius;

            mStrokeColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_strokeColor, default_border_color);
            mCheckedStrokeColor = attrsArray.getColor(R.styleable.TagsFlowlayout_tag_checkedStrokeColor, default_checked_border_color);
            mStrokeWidth = (int) attrsArray.getDimension(R.styleable.TagsFlowlayout_tag_strokeWidth, mStrokeWidth);


        } finally {
            attrsArray.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        measureChildren(widthMeasureSpec, heightMeasureSpec);

        int width;
        int height = 0;

        int row = 0; // The row counter.
        int rowWidth = 0; // Calc the current row width.
        int rowMaxHeight = 0; // Calc the max tag height, in current row.

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            final int childWidth = child.getMeasuredWidth();
            final int childHeight = child.getMeasuredHeight();

            if (child.getVisibility() != GONE) {
                rowWidth += childWidth;
                if (rowWidth > widthSize) { // Next line.
                    rowWidth = childWidth; // The next row width.
                    height += rowMaxHeight + verticalSpacing;
                    rowMaxHeight = childHeight; // The next row max height.
                    row++;
                } else { // This line.
                    rowMaxHeight = Math.max(rowMaxHeight, childHeight);
                }
                rowWidth += horizontalSpacing;
            }
        }
        // Account for the last row height.
        height += rowMaxHeight;

        // Account for the padding too.
        height += getPaddingTop() + getPaddingBottom();

        // If the tags grouped in one row, set the width to wrap the tags.
        if (row == 0) {
            width = rowWidth;
            width += getPaddingLeft() + getPaddingRight();
        } else {// If the tags grouped exceed one line, set the width to match the parent.
            width = widthSize;
        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width,
                heightMode == MeasureSpec.EXACTLY ? heightSize : height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int parentLeft = getPaddingLeft();
        final int parentRight = r - l - getPaddingRight();
        final int parentTop = getPaddingTop();
        final int parentBottom = b - t - getPaddingBottom();

        int childLeft = parentLeft;
        int childTop = parentTop;

        int rowMaxHeight = 0;

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            final int width = child.getMeasuredWidth();
            final int height = child.getMeasuredHeight();

            if (child.getVisibility() != GONE) {
                if (childLeft + width > parentRight) { // Next line
                    childLeft = parentLeft;
                    childTop += rowMaxHeight + verticalSpacing;
                    rowMaxHeight = height;
                } else {
                    rowMaxHeight = Math.max(rowMaxHeight, height);
                }
                child.layout(childLeft, childTop, childLeft + width, childTop + height);

                childLeft += width + horizontalSpacing;
            }
        }
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.tags = getTags();
        ss.checkedPosition = getCheckedTagIndex();
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        setTags(ss.tags);
        TagView checkedTagView = getTagAt(ss.checkedPosition);
        if (checkedTagView != null) {
            checkedTagView.setChecked(true);
        }
    }

    /**
     * Return the last NORMAL state tag view in this group.
     *
     * @return the last NORMAL state tag view or null if not exists
     */
    protected TagView getLastTagView() {
        final int lastNormalTagIndex = getChildCount() - 1;
        return getTagAt(lastNormalTagIndex);
    }

    /**
     * Returns the tag array in group, except the INPUT tag.
     *
     * @return the tag array.
     */
    public String[] getTags() {
        final int count = getChildCount();
        final List<String> tagList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            final TagView tagView = getTagAt(i);
            tagList.add(tagView.getText().toString());
        }

        return tagList.toArray(new String[tagList.size()]);
    }

    /**
     * @see #setTags(String...)
     */
    public void setTags(List<String> tagList) {
        setTags(tagList.toArray(new String[tagList.size()]));
    }

    /**
     * Set the tags. It will remove all previous tags first.
     *
     * @param tags the tag list to set.
     */
    public void setTags(String... tags) {
        removeAllViews();
        for (final String tag : tags) {
            appendTag(tag);
        }
    }

    /**
     * Returns the tag view at the specified position in the group.
     *
     * @param index the position at which to get the tag view from.
     * @return the tag view at the specified position or null if the position
     * does not exists within this group.
     */
    protected TagView getTagAt(int index) {
        return null == getChildAt(index) ? null : (TagView) getChildAt(index);
    }

    /**
     * Returns the checked tag view in the group.单选时候有用,多选时候返回第一个
     *
     * @return the checked tag view or null if not exists.
     */
    protected TagView getCheckedTag() {
        final int checkedTagIndex = getCheckedTagIndex();
        if (checkedTagIndex != -1) {
            return getTagAt(checkedTagIndex);
        }
        return null;
    }

    /**
     * Returns the checked tag view in the group.单选时候有用,多选时候返回第一个
     *
     * @return the checked tag view or null if not exists.
     */
    protected String getCheckedTagText() {
        if (null != getCheckedTag()) {
            return getCheckedTag().getText().toString();
        }
        return null;
    }

    /**
     * 返回选中的tag的文字
     * Returns the tag array in group, except the INPUT tag.
     *
     * @return the tag array.
     */
    public String[] getCheckedTagsText() {
        final int count = getChildCount();
        final List<String> tagList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            final TagView tagView = getTagAt(i);
            if (tagView.isChecked()) {
                tagList.add(tagView.getText().toString());
            }
        }

        return tagList.toArray(new String[tagList.size()]);
    }

    /**
     * 返回选中的tag的文字
     * Returns the tag array in group, except the INPUT tag.
     *
     * @return the tag array.
     */
    public ArrayList<String> getCheckedTagsTextsArrayList() {
        final int count = getChildCount();
        final ArrayList<String> tagList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            final TagView tagView = getTagAt(i);
            if (tagView.isChecked()) {
                tagList.add(tagView.getText().toString());
            }
        }

        return tagList;
    }

    /**
     * 单选时候有用,多选时候返回第一个
     * Return the checked tag index.
     *
     * @return the checked tag index, or -1 if not exists.
     */
    protected int getCheckedTagIndex() {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final TagView tag = getTagAt(i);
            if (tag.isChecked()) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 返回选中的tag的索引
     * Returns the tag array in group, except the INPUT tag.
     *
     * @return the tag array.
     */
    public ArrayList<Integer> getCheckedTagsIndexArrayList() {
        final int count = getChildCount();
        final ArrayList<Integer> tagList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            final TagView tagView = getTagAt(i);
            if (tagView.isChecked()) {
                tagList.add(i);
            }
        }

        return tagList;
    }

    /**
     * 取消选中状态
     */
    public void setTagsUnchecked() {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            TagView tag = getTagAt(i);
            if (null != tag && tag.isChecked()) {
                tag.setChecked(false);
            }
        }
    }

    /**
     * 选中
     *
     * @param index
     */
    public void setTagCheckedWithIndex(int index) {
        getTagAt(index).setChecked(true);
    }

    /**
     * Append tag to this group.
     *
     * @param tag the tag to append.
     */
    public void appendTag(CharSequence tag) {
        final TagView newTag = new TagView(getContext(), tag);
        newTag.setOnClickListener(mInternalTagClickListener);
        addView(newTag);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new TagsFlowlayout.LayoutParams(getContext(), attrs);
    }

    /**
     * Register a callback to be invoked when a tag is clicked.
     *
     * @param l the callback that will run.
     */
    public void setOnTagClickListener(OnTagClickListener l) {
        mOnTagClickListener = l;
    }

    /**
     * 设置是否支持多选
     *
     * @param multiChooseable
     */
    public void setMultiChooseable(boolean multiChooseable) {
        this.multiChooseable = multiChooseable;
    }

    /**
     * Interface definition for a callback to be invoked when a tag is clicked.
     */
    public interface OnTagClickListener {
        /**
         * Called when a tag has been clicked.
         *
         * @param tag The tag text of the tag that was clicked.
         */
        void onTagClick(String tag);
    }

    /**
     * Per-child layout information for layouts.
     */
    public static class LayoutParams extends ViewGroup.LayoutParams {
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }
    }

    /**
     * For {@link TagsFlowlayout} save and restore state.
     */
    static class SavedState extends BaseSavedState {
        public static final Creator<SavedState> CREATOR =
                new Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
        int tagCount;
        String[] tags;
        int checkedPosition;

        public SavedState(Parcel source) {
            super(source);
            tagCount = source.readInt();
            tags = new String[tagCount];
            source.readStringArray(tags);
            checkedPosition = source.readInt();
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            tagCount = tags.length;
            dest.writeInt(tagCount);
            dest.writeStringArray(tags);
            dest.writeInt(checkedPosition);
        }
    }

    /**
     * The tag view click listener for internal use.
     */
    class InternalTagClickListener implements OnClickListener {
        @Override
        public void onClick(View v) {
            final TagView tag = (TagView) v;

            final TagView checkedTag = getCheckedTag();
            if (!multiChooseable) {
                // 单选
                if (checkedTag != null) {
                    checkedTag.setChecked(false);
                    if (checkedTag != tag) {
                        tag.setChecked(true);
                    }
                } else {
                    tag.setChecked(true);
                }
            } else {
                // 多选
                tag.setChecked(!tag.isChecked());
            }

            // 外部点击事件
            if (mOnTagClickListener != null) {
                mOnTagClickListener.onTagClick(tag.getText().toString());
            }
        }
    }

    /*************************************************
     * 标签选中的时候控件切换状态,继承现有的CheckedTextView,
     * 其实现了Checkable接口,不用做什么操作了
     *************************************************/
    class TagView extends TextView implements Checkable{
        /**
         * The offset to the text.
         */
        private static final int CHECKED_MARKER_OFFSET = 3;

        /**
         * Indicates the tag if checked.
         */
        private boolean isChecked = false;

        /**
         * Indicates the tag if pressed.
         */
        private boolean isPressed = false;

        private Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        private Paint mCheckedMarkerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        /**
         * The rect for the tag's left corner drawing.
         */
        private RectF mLeftCornerRectF = new RectF();

        /**
         * The rect for the tag's right corner drawing.
         */
        private RectF mRightCornerRectF = new RectF();

        /**
         * The rect for the tag's horizontal blank fill area.
         */
        private RectF mHorizontalBlankFillRectF = new RectF();

        /**
         * The rect for the tag's vertical blank fill area.
         */
        private RectF mVerticalBlankFillRectF = new RectF();

        /**
         * The rect for the checked mark draw bound.
         */
        private RectF mCheckedMarkerBound = new RectF();

        /**
         * Used to detect the touch event.
         */
        private Rect mOutRect = new Rect();

        /**
         * The path for draw the tag's outline border.
         */
        private Path mBorderPath = new Path();

        {
            mBorderPaint.setStyle(Paint.Style.STROKE);
            mBorderPaint.setStrokeWidth(mStrokeWidth);
            mBackgroundPaint.setStyle(Paint.Style.FILL);
            mCheckedMarkerPaint.setStyle(Paint.Style.FILL);
            mCheckedMarkerPaint.setStrokeWidth(mStrokeWidth);
            mCheckedMarkerPaint.setColor(mCheckedStrokeColor);
        }

        public TagView(Context context, CharSequence text) {
            super(context);
            setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);

            setLayoutParams(new TagsFlowlayout.LayoutParams(TagsFlowlayout.LayoutParams.WRAP_CONTENT, TagsFlowlayout.LayoutParams.WRAP_CONTENT));

            setGravity(Gravity.CENTER);

            setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);

            setText(text);
            invalidatePaint();
//            if (chooseable) { // 可选的时候才显示选中效果,否则直接点击操作
//                setBackgroundResource(R.drawable.bg_sku_tagview_selector);
//                setTextColor(new ColorStateList(new int[][]{
//                        new int[]{android.R.attr.state_checked},
//                        new int[]{}
//                },
//                        new int[]{getResources().getColor(android.R.color.white), getResources().getColor(R.color.common_666666)}
//                ));
//            } else {
//                setBackgroundResource(R.drawable.sku_item_bg_cannot_choose_selector);
//                setTextColor(getResources().getColor(R.color.common_666666));
//            }
        }


        @Override
        public void setChecked(boolean checked) {
            isChecked = checked;
            invalidatePaint();
        }

        @Override
        public boolean isChecked() {
            return isChecked;
        }

        @Override
        public void toggle() {
            setChecked(!isChecked());
        }

        private void invalidatePaint() {
            if (isChecked) {
                mBorderPaint.setColor(mCheckedStrokeColor);
                mBackgroundPaint.setColor(checkedBackgroundColor);
                setTextColor(checkedTextColor);
            } else {
                mBorderPaint.setColor(mStrokeColor);
                mBackgroundPaint.setColor(backgroundColor);
                setTextColor(textColor);
            }

            if (isPressed) {
                mBackgroundPaint.setColor(pressedBackgroundColor);
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawArc(mLeftCornerRectF, -180, 90, true, mBackgroundPaint);
            canvas.drawArc(mLeftCornerRectF, -270, 90, true, mBackgroundPaint);
            canvas.drawArc(mRightCornerRectF, -90, 90, true, mBackgroundPaint);
            canvas.drawArc(mRightCornerRectF, 0, 90, true, mBackgroundPaint);
            canvas.drawRect(mHorizontalBlankFillRectF, mBackgroundPaint);
            canvas.drawRect(mVerticalBlankFillRectF, mBackgroundPaint);

            if (isChecked) {
                canvas.save();
                canvas.rotate(45, mCheckedMarkerBound.centerX(), mCheckedMarkerBound.centerY());
                canvas.drawLine(mCheckedMarkerBound.left, mCheckedMarkerBound.centerY(),
                        mCheckedMarkerBound.right, mCheckedMarkerBound.centerY(), mCheckedMarkerPaint);
                canvas.drawLine(mCheckedMarkerBound.centerX(), mCheckedMarkerBound.top,
                        mCheckedMarkerBound.centerX(), mCheckedMarkerBound.bottom, mCheckedMarkerPaint);
                canvas.restore();
            }
            canvas.drawPath(mBorderPath, mBorderPaint);
            super.onDraw(canvas);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            int left = mStrokeWidth;
            int top = mStrokeWidth;
            int right = left + w - mStrokeWidth * 2;
            int bottom = top + h - mStrokeWidth * 2;

            int d = bottom - top;

            mLeftCornerRectF.set(left, top, left + d, top + d);
            mRightCornerRectF.set(right - d, top, right, top + d);

            mBorderPath.reset();
            mBorderPath.addArc(mLeftCornerRectF, -180, 90);
            mBorderPath.addArc(mLeftCornerRectF, -270, 90);
            mBorderPath.addArc(mRightCornerRectF, -90, 90);
            mBorderPath.addArc(mRightCornerRectF, 0, 90);

            int l = (int) (d / 2.0f);
            mBorderPath.moveTo(left + l, top);
            mBorderPath.lineTo(right - l, top);

            mBorderPath.moveTo(left + l, bottom);
            mBorderPath.lineTo(right - l, bottom);

            mBorderPath.moveTo(left, top + l);
            mBorderPath.lineTo(left, bottom - l);

            mBorderPath.moveTo(right, top + l);
            mBorderPath.lineTo(right, bottom - l);

            mHorizontalBlankFillRectF.set(left, top + l, right, bottom - l);
            mVerticalBlankFillRectF.set(left + l, top, right - l, bottom);

            int m = (int) (h / 2.5f);
            h = bottom - top;
            mCheckedMarkerBound.set(right - m - horizontalPadding + CHECKED_MARKER_OFFSET,
                    top + h / 2 - m / 2,
                    right - horizontalPadding + CHECKED_MARKER_OFFSET,
                    bottom - h / 2 + m / 2);

            // Ensure the checked mark drawing region is correct across screen orientation changes.
            if (isChecked) {
                setPadding(horizontalPadding,
                        verticalPadding,
                        (int) (horizontalPadding + h / 2.5f + CHECKED_MARKER_OFFSET),
                        verticalPadding);
            }
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    getDrawingRect(mOutRect);
                    isPressed = true;
                    invalidatePaint();
                    invalidate();
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    if (!mOutRect.contains((int) event.getX(), (int) event.getY())) {
                        isPressed = false;
                        invalidatePaint();
                        invalidate();
                    }
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    isPressed = false;
                    invalidatePaint();
                    invalidate();
                    break;
                }
            }
            return super.onTouchEvent(event);
        }
    }
}